package zheezes.jui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.MalformedURLException;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;

import org.apache.log4j.Logger;

import zheezes.mail.ZSmtp;
import zheezes.util.ZCast;
import zheezes.util.ZFileFilter;
import zheezes.util.ZLog4j;
import zheezes.util.ZThread;

/**
 * @author hcconquer@gmail.com
 * @create 2013-01-29
 */
public class JMail extends ZFrame {
	public final static Logger log = Logger.getLogger(JMail.class);

	public final static int MODULE_MAIL_TABLE = 1;

	private JFrame frame;
	private ZAbout dlgAbout = new ZAbout();
	private JFileChooser chFile = new JFileChooser();
	
	private final Action actLoadMail = new LoadMailAction();
	private final Action actSaveResult = new SaveResAction();
	private final Action actAddRow = new AddRowAction();
	private final Action actRemRow = new RemRowAction();
	private final Action actCheckAll = new CheckAllAction();
	private final Action actCheckSucc = new CheckSuccAction();
	private final Action actCheckFail = new CheckFailAction();
	private final Action actAbout = new ShowAboutAction();

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		ZLog4j.configConsole();
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					JMail window = new JMail();
					window.frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public JMail() {
		initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		frame = new JFrame();
		frame.setTitle(ResMgr.APP_NAME);
		frame.setIconImage(Toolkit.getDefaultToolkit().getImage(
				ResMgr.get(ResMgr.IMAGE_JMAIL)));
		frame.setBounds(100, 100, 450, 300);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		JMenuBar menuBar = new JMenuBar();
		frame.setJMenuBar(menuBar);

		JMenu mnFile = new JMenu("File");
		menuBar.add(mnFile);

		JMenuItem mntmLoad = new JMenuItem();
		mntmLoad.setAction(actLoadMail);
		mnFile.add(mntmLoad);

		JMenuItem mntmSave = new JMenuItem();
		mntmSave.setAction(actSaveResult);
		mnFile.add(mntmSave);

		JMenu mnEdit = new JMenu("Edit");
		menuBar.add(mnEdit);

		JMenuItem mntmAddRow = new JMenuItem();
		mnEdit.add(mntmAddRow);
		mntmAddRow.setAction(actAddRow);

		JMenuItem mntmRemRow = new JMenuItem();
		mnEdit.add(mntmRemRow);
		mntmRemRow.setAction(actRemRow);

		JMenu mnCommand = new JMenu();
		mnCommand.setText("Check");
		menuBar.add(mnCommand);

		JMenuItem mntmCheckMail = new JMenuItem();
		mnCommand.add(mntmCheckMail);
		mntmCheckMail.setAction(actCheckAll);

		JMenuItem mntmCheckSucc = mnCommand.add(actCheckSucc);
		mntmCheckSucc.setAction(actCheckSucc);
		mnCommand.add(mntmCheckSucc);

		JMenuItem mntmCheckFail = new JMenuItem();
		mntmCheckFail.setAction(actCheckFail);
		mnCommand.add(mntmCheckFail);
		
		JMenu mnHelp = new JMenu("Help");
		menuBar.add(mnHelp);
		
		JMenuItem mntmAbout = new JMenuItem();
		mntmAbout.setAction(actAbout);
		mnHelp.add(mntmAbout);

		JToolBar toolBar = new JToolBar();
		toolBar.setFloatable(false);
		frame.getContentPane().add(toolBar, BorderLayout.NORTH);

		JButton btnCheck = new JButton();
		btnCheck.setIcon(ResMgr.getIcon(ResMgr.IMAGE_START));
		btnCheck.setForeground(Color.WHITE);
		toolBar.add(btnCheck);
		btnCheck.addActionListener(actCheckAll);

		JScrollPane spTable = new JScrollPane();
		frame.getContentPane().add(spTable, BorderLayout.CENTER);

		JTable tblMail = new JTable(new MailTableModel());
		spTable.setViewportView(tblMail);
		ZTable.setColAlign(tblMail, MailTableModel.COL_MAIL,
				SwingConstants.CENTER);
		ZTable.setColAlign(tblMail, MailTableModel.COL_RSTR,
				SwingConstants.CENTER);
		ZTable.hideColumn(tblMail, MailTableModel.COL_RES);
		modput(MODULE_MAIL_TABLE, tblMail);

		chFile.addChoosableFileFilter(new ZFileFilter(new String[] { ".txt" }));
	}

		@SuppressWarnings({ "rawtypes", "unchecked", "serial" })
		private class MailTableModel extends DefaultTableModel {
			public final static int COL_MAIL = 0;
			public final static int COL_RSTR = 1;
			public final static int COL_RES = 2;
	
			private Class[] columnTypes = new Class[] { String.class, String.class,
					Integer.class };
			private String[] columnNames = { "Mail", "Result", "" };
			private boolean[] columnEditables = new boolean[] { true, false, false };
	
			public MailTableModel() {
			}
	
			public int getColumnCount() {
				return columnNames.length;
			}
	
			public Class getColumnClass(int column) {
				return columnTypes[column];
			}
	
			public String getColumnName(int column) {
				return columnNames[column];
			}
	
			public boolean isCellEditable(int row, int column) {
				return columnEditables[column];
			}
	
			/*
			 * public void setValueAt(Object aValue, int row, int column) {
			 * super.setValueAt(aValue, row, column);
			 * 
			 * if ((row == getRowCount() - 1) && !rownull(row)) { addRow(new
			 * Object[getColumnCount()]); } }
			 */
	
			@SuppressWarnings("unused")
			private boolean rownull(int row) {
				if (row < 0 || row >= getRowCount()) {
					return false;
				}
				int count = getColumnCount();
				for (int col = 0; col < count; col++) {
					if (getValueAt(row, col) != null) {
						return false;
					}
				}
				return true;
			}
	
			@SuppressWarnings("unused")
			private boolean rowblank(int row) {
				if (row < 0 || row >= getRowCount()) {
					return false;
				}
				int count = getColumnCount();
				for (int col = 0; col < count; col++) {
					Object value = getValueAt(row, col);
					if (value != null && !value.toString().isEmpty()) {
						return false;
					}
				}
				return true;
			}
		}

	private int loadMail(File file) {
		try {
			FileReader fr = new FileReader(file);
			BufferedReader br = new BufferedReader(fr);
			// htmlKit.read(reader, htmlDoc, 0);
			JTable tblMail = (JTable) modget(MODULE_MAIL_TABLE);
			DefaultTableModel tmMail = (DefaultTableModel) tblMail.getModel();
			String line = null;
			while ((line = br.readLine()) != null) {
				int at = line.indexOf('@');
				if (at < 0) {
					continue;
				}
				for (int i = at; i < line.length(); i++) {
					if (Character.isWhitespace(line.charAt(i))) {
						line = line.substring(0, i);
					}
				}
				tmMail.addRow(new Object[] { line });
			}
			br.close();
			fr.close();
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		} catch (IOException e1) {
			e1.printStackTrace();
		}

		return 0;
	}

	private int saveResult(File file) {
		JTable tblMail = (JTable) modget(MODULE_MAIL_TABLE);
		DefaultTableModel tmMail = (DefaultTableModel) tblMail.getModel();
		int count = tmMail.getRowCount();
		String line = null, mail = null, result = null;
		BufferedWriter bw = null;
		try {
			bw = new BufferedWriter(new FileWriter(file));

			for (int row = 0; row < count; row++) {
				mail = (String) tmMail.getValueAt(row, MailTableModel.COL_MAIL);
				result = (String) tmMail.getValueAt(row,
						MailTableModel.COL_RSTR);
				if (result == null) {
					result = "";
				}
				line = String.format("%s\t%s\t\n", mail, result);

				bw.write(line);

			}
			// bw.close();
		} catch (IOException e) {
			log.debug(e.getMessage(), e);
		} finally {
			try {
				if (bw != null) {
					bw.close();
				}
			} catch (IOException e) {
				log.debug(e.getMessage(), e);
			}
		}
		return 0;
	}

	private void clearResult(int type) {
		JTable tblMail = (JTable) modget(MODULE_MAIL_TABLE);
		DefaultTableModel tmMail = (DefaultTableModel) tblMail.getModel();
		int count = tmMail.getRowCount();
		for (int row = 0; row < count; row++) {
			Integer res = (Integer) tmMail.getValueAt(row,
					MailTableModel.COL_RES);
			log.debug(String.format("value: %d", ZCast.cast(res)));
			if (res != null && res.intValue() * type < 0) {
				continue;
			}
			tmMail.setValueAt(null, row, MailTableModel.COL_RSTR);
		}
	}

	private void checkMail(int type) {
		JTable tblMail = (JTable) modget(MODULE_MAIL_TABLE);
		DefaultTableModel tmMail = (DefaultTableModel) tblMail.getModel();
		int count = tmMail.getRowCount();
		for (int row = 0; row < count; row++) {
			String rstr = (String) tmMail.getValueAt(row,
					MailTableModel.COL_RSTR);
			if (rstr != null && rstr.length() > 0) {
				continue;
			}
			String mail = (String) tmMail.getValueAt(row,
					MailTableModel.COL_MAIL);
			if (mail == null || mail.length() == 0) {
				continue;
			}
			int code = ZSmtp.checkMail(mail, -1, null, null, 6000, 10);
			log.debug(String.format("mail: %s, code: %d", mail, code));
			SwingUtilities.invokeLater(new ZThread(tmMail, row, code) {
				@Override
				public void run() {
					DefaultTableModel tmMail = (DefaultTableModel) ZCast.cast(
							args[0], DefaultTableModel.class);
					Integer row = (Integer) ZCast.cast(args[1], Integer.class);
					Integer code = (Integer) ZCast.cast(args[2], Integer.class);
					tmMail.setValueAt(ZSmtp.strcode(code), row,
							MailTableModel.COL_RSTR);
					tmMail.setValueAt(code, row, MailTableModel.COL_RES);
				}
			});
		}
	}

	@SuppressWarnings("serial")
	private class LoadMailAction extends AbstractAction {
		public LoadMailAction() {
			putValue(ACCELERATOR_KEY,
					KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_MASK));
			putValue(NAME, "Load");
			putValue(SHORT_DESCRIPTION, "Load mail");
		}

		public void actionPerformed(ActionEvent event) {
			int ret = chFile.showOpenDialog(frame);
			if (ret != JFileChooser.APPROVE_OPTION) {
				log.debug(String.format("File: %d\n", ret));
				return;
			}
			File file = chFile.getSelectedFile();
			if (file == null || !file.exists() || !file.canRead()) {
				return;
			}
			loadMail(file);
			try {
				frame.setTitle(file.toURI().toURL().toString());
			} catch (MalformedURLException e) {
				e.printStackTrace();
			}
		}
	}

	@SuppressWarnings("serial")
	private class SaveResAction extends AbstractAction {
		public SaveResAction() {
			putValue(ACCELERATOR_KEY,
					KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_MASK));
			putValue(SMALL_ICON, ResMgr.getIcon(ResMgr.IMAGE_SAVE));
			putValue(NAME, "Save");
			putValue(SHORT_DESCRIPTION, "Save to file");
		}

		public void actionPerformed(ActionEvent e) {
			int ret = chFile.showSaveDialog(frame);
			if (ret != JFileChooser.APPROVE_OPTION) {
				log.debug(String.format("File: %d\n", ret));
				return;
			}
			File file = chFile.getSelectedFile();
			if (file == null || !file.exists() || !file.canRead()) {
				return;
			}
			saveResult(file);
		}
	}

	@SuppressWarnings("serial")
	private class AddRowAction extends AbstractAction {
		public AddRowAction() {
			putValue(ACCELERATOR_KEY,
					KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_MASK));
			putValue(SMALL_ICON, ResMgr.getIcon(ResMgr.IMAGE_ADD));
			putValue(NAME, "Add");
			putValue(SHORT_DESCRIPTION, "Add row");
		}

		public void actionPerformed(ActionEvent e) {
			JTable tblMail = (JTable) modget(MODULE_MAIL_TABLE);
			DefaultTableModel tmMail = (DefaultTableModel) tblMail.getModel();
			// int row = tblMail.getSelectedRow();
			tmMail.addRow(new Object[tmMail.getColumnCount()]);
			// tmMail.removeRow(row);
		}
	}

	@SuppressWarnings("serial")
	private class RemRowAction extends AbstractAction {
		public RemRowAction() {
			putValue(ACCELERATOR_KEY,
					KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.CTRL_MASK));
			putValue(SMALL_ICON, ResMgr.getIcon(ResMgr.IMAGE_REMOVE));
			putValue(NAME, "Remove");
			putValue(SHORT_DESCRIPTION, "Remove row");
		}

		public void actionPerformed(ActionEvent e) {
			JTable tblMail = (JTable) modget(MODULE_MAIL_TABLE);
			DefaultTableModel tmMail = (DefaultTableModel) tblMail.getModel();
			int row = tblMail.getSelectedRow();
			tmMail.removeRow(row);
		}
	}

	@SuppressWarnings("serial")
	private class CheckAllAction extends AbstractAction {
		public CheckAllAction() {
			putValue(SMALL_ICON, ResMgr.getIcon(ResMgr.IMAGE_START));
			putValue(ACCELERATOR_KEY,
					KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_MASK));
			putValue(NAME, "All");
			putValue(SHORT_DESCRIPTION, "Check all");
		}

		public void actionPerformed(ActionEvent e) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					clearResult(0);
					checkMail(0);
				}
			}).start();
		}
	}

	@SuppressWarnings("serial")
	private class CheckSuccAction extends AbstractAction {
		public CheckSuccAction() {
			putValue(NAME, "Succ");
			putValue(SHORT_DESCRIPTION, "Check succ");
		}

		public void actionPerformed(ActionEvent e) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					clearResult(1);
					checkMail(1);
				}
			}).start();
		}
	}

	@SuppressWarnings("serial")
	private class CheckFailAction extends AbstractAction {
		public CheckFailAction() {
			putValue(NAME, "Fail");
			putValue(SHORT_DESCRIPTION, "Check fail");
		}

		public void actionPerformed(ActionEvent e) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					clearResult(-1);
					checkMail(-1);
				}
			}).start();
		}
	}

	@SuppressWarnings("serial")
	private class ShowAboutAction extends AbstractAction {
		public ShowAboutAction() {
			putValue(NAME, "About");
			putValue(SHORT_DESCRIPTION, "About");
		}
		public void actionPerformed(ActionEvent e) {
			dlgAbout.setVisible(true);
		}
	}
}
